home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / dialog / html.c < prev    next >
C/C++ Source or Header  |  1996-08-03  |  26KB  |  1,070 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #include <limits.h>
  5. #include <time.h>
  6. #include <sys/stat.h>
  7. #include "dialog.h"
  8. #include "diadef.h"
  9. #include "internal.h"
  10. #include "cmdsock.h"
  11. #include "dialog.m"
  12. #include "../paths.h"
  13. #include "../userconf/userconf.h"
  14. #include "../netconf/netconf.h"
  15.  
  16. static char *html_host = NULL;
  17. static int html_cli;        // Handle use to talk back to client
  18. static int port;
  19. static int target_level;
  20. static int history_level;
  21. static int debug;
  22. static int html_java;    // Produce HTML code or command for the java
  23.                         // front end
  24. static HTML_VARVAL *curvars;
  25. static MENU_STATUS html_submit;    // Button action to process
  26. static int html_postdone;    // Did the POST was processed
  27. static int html_drawdone;    // Insure that we draw a html page only once
  28. static char html_popup=0;
  29.  
  30. struct LEVEL_INFO{
  31.     MENU_STATUS status;
  32.     SSTRING key;
  33.     SSTRING title;
  34. };
  35. static LEVEL_INFO tblevel[20];
  36. static int level = 0;
  37.  
  38. static const char *html_getval (int lev, const char *key)
  39. {
  40.     char bufkey[200];
  41.     sprintf (bufkey,"%d_%s",lev,key);
  42.     const char *ret = "";
  43.     if (curvars != NULL) ret = curvars->getval(bufkey);
  44.     return ret;
  45.  
  46. }
  47.  
  48. /*
  49.     Get the new value of a field
  50. */
  51. const char *html_getval (const char *key)
  52. {
  53.     return html_getval (level,key);
  54. }
  55.  
  56. /*
  57.     Check if a button exist as a variable (the user has clicked on it)
  58. */
  59. static int html_butexist (const char *key)
  60. {
  61.     int ret = 0;
  62.     if (curvars != NULL) ret = curvars->exist(key);
  63.     return ret;
  64. }
  65.  
  66. static void html_reset()
  67. {
  68.     // Variable a simply never forgotten. Some primitive form
  69.     // of garbage collection in varval.c take care of too old entries
  70.     curvars = NULL;
  71.     html_postdone = 0;
  72.     html_drawdone = 0;
  73.     html_popup=0;
  74. }
  75.  
  76. /*
  77.     Get the original value of a field
  78. */
  79. const char *html_getoldval (const char *key)
  80. {
  81.     char oldkey[100];
  82.     sprintf (oldkey,"CUR_%s",key);
  83.     return html_getval (oldkey);
  84. }
  85.  
  86. /*
  87.     Generate a <input command to define a field
  88. */
  89. void html_defvar (
  90.     const char *type,
  91.     const char *name,
  92.     const char *value,
  93.     const char *opt)
  94. {
  95.     html_printf ("<input type=%s name=\"%d_%s\" value=\"%s\" %s>\n"
  96.         ,type,level,name,value,opt);
  97. }
  98. void html_defvar (
  99.     const char *type,
  100.     const char *name,
  101.     int value,
  102.     const char *opt)
  103. {
  104.     char tmp[20];
  105.     sprintf (tmp,"%d",value);
  106.     html_defvar (type,name,tmp,opt);
  107. }
  108. /*
  109.     Generate a <input command to define the current value of a field
  110. */
  111. void html_defvarcur (
  112.     const char *name,
  113.     const char *value)
  114. {
  115.     html_printf ("<input type=hidden name=\"%d_CUR_%s\" value=\"%s\">\n"
  116.         ,level,name,value);
  117. }
  118. void html_defvarcur (
  119.     const char *name,
  120.     int value)
  121. {
  122.     char tmp[20];
  123.     sprintf (tmp,"%d",value);
  124.     html_defvarcur (name,tmp);
  125. }
  126.  
  127.  
  128. static char *html_buf;
  129. static int html_len;
  130. static int html_maxlen;
  131.  
  132. void html_printf (const char *ctl, ...)
  133. {
  134.     va_list list;
  135.     va_start (list,ctl);
  136.     char buf[1000];
  137.     int len = vsprintf (buf,ctl,list);
  138.     va_end (list);
  139.     if (html_len + len > html_maxlen){
  140.         html_maxlen += 5000;
  141.         html_buf = (char*)realloc(html_buf,html_maxlen);
  142.     }
  143.     strcpy (html_buf+html_len,buf);
  144.     html_len += len;
  145. }
  146.  
  147. void html_flush ()
  148. {
  149.     if (html_len > 0){
  150.         write (html_cli,html_buf,html_len);
  151.         html_len = 0;
  152.     }
  153. }
  154.  
  155. /*
  156.     Record the host name and port number to encode in URLs
  157. */
  158. void html_sethost (const char *_hostname, int _port)
  159. {
  160.     free (html_host);
  161.     html_host = strdup(_hostname);
  162.     port = _port;
  163. }
  164.  
  165. static char KEY_ACCEPT[]="accept";
  166. static char KEY_DEL[]="del";
  167. static char KEY_OK[]="ok";
  168. static char KEY_ADD[]="add";
  169. static char KEY_EDIT[]="edit";
  170. static char KEY_YES[]="yes";
  171. static char KEY_NO[]="no";
  172.  
  173. /*
  174.     Format a path to a sub-meny entry
  175. */
  176. static void html_setpath_level(char *path, int upto)
  177. {
  178.     char *pt = path;
  179.     LEVEL_INFO *ptl = tblevel;
  180.     for (int i=0; i<upto; i++,ptl++){
  181.         const char *key = KEY_OK;
  182.         if (ptl->status == MENU_DEL){
  183.             key = KEY_DEL;
  184.         }else if (ptl->status == MENU_ACCEPT){
  185.             key = KEY_ACCEPT;
  186.         }else if (ptl->status == MENU_ADD){
  187.             key = KEY_ADD;
  188.         }else if (ptl->status == MENU_EDIT){
  189.             key = KEY_EDIT;
  190.         }else if (ptl->status == MENU_YES){
  191.             key = KEY_YES;
  192.         }else if (ptl->status == MENU_NO){
  193.             key = KEY_NO;
  194.         }
  195.         pt += sprintf (pt,"%s,%s/",key,ptl->key.get());
  196.     }
  197.     *pt = '\0';
  198. }
  199. /*
  200.     Format a context to a sub-meny entry
  201. */
  202. static void html_setcontext_level(char *path, int upto)
  203. {
  204.     char *pt = path;
  205.     LEVEL_INFO *ptl = tblevel;
  206.     for (int i=0; i<upto; i++,ptl++){
  207.         pt += sprintf (pt,"%s/",ptl->key.get());
  208.     }
  209.     *pt = '\0';
  210. }
  211. /*
  212.     Format a path to a sub-meny entry
  213. */
  214. static void html_setpath(char *path)
  215. {
  216.     html_setpath_level (path,level);
  217. }
  218. /*
  219.     Set a url pointing to a sub-menu entry
  220. */
  221. void html_setaref (
  222.     const char *key,    // Key for the url (path indeed)
  223.     const char *text)    // Highlit text
  224. {
  225.  
  226.     char path[PATH_MAX];
  227.     html_setpath (path);
  228.     html_printf ("<A HREF=\"http://%s:%d/html:/%sok,%s\">%s</A>"
  229.         ,html_host,port,path,key,text);
  230. }
  231.  
  232.  
  233. /*
  234.     Format a message suitable as a path component of a URL.
  235.     Space are transformed to ==.
  236. */
  237. void html_formatkey (char *key, const char *ctl, ...)
  238. {
  239.     va_list list;
  240.     va_start (list,ctl);
  241.     char buf[1000];
  242.     vsprintf (buf,ctl,list);
  243.     va_end (list);
  244.     char *pt = buf;
  245.     while (*pt != '\0'){
  246.         char carac = *pt++;
  247.         if (carac == ' ' || carac == '/'){
  248.             *key++ = '=';
  249.             *key++ = '=';
  250.         }else{
  251.             *key++ = carac;
  252.         }
  253.     }
  254.     *key = '\0';
  255. }
  256.  
  257. /*
  258.     Send the header of the html document.
  259. */
  260. static void html_sendintro(
  261.     const char *content_type,
  262.     int length,        // Length or -1
  263.     int expires)    // How much seconds this document is expected to
  264.                     // be valid
  265. {
  266.     time_t tim = time(NULL);
  267.  
  268.     html_printf ("HTTP/1.0 200 Document follows\r\n");
  269.     html_printf ("MIME-Version: 1.0\r\n");
  270.     extern char *revision;
  271.     html_printf ("Server: linuxconf/%s\r\n",revision);
  272.     char buf[200];
  273.     tim += expires;
  274.     strcpy (buf,asctime(localtime(&tim)));
  275.     strip_end (buf);
  276.     html_printf ("Date: %s\r\n",buf);
  277.     html_printf ("Content-Type: %s\r\n",content_type);
  278.     if (length != -1){
  279.         html_printf ("Content-Length: %d\r\n",length);
  280.     }
  281.     html_printf ("Expires: %s\r\n",buf);
  282.     html_printf ("Last-Modified: %s\r\n",buf);
  283.     html_printf ("\r\n");
  284. }
  285.  
  286. static CMDSOCK *cmd = NULL;
  287. /*
  288.     Indicate that the html page has been sent and the connection can
  289.     be closed.
  290. */
  291. static void html_setdone()
  292. {
  293.     html_drawdone = 1;
  294.     html_flush ();
  295.     if (cmd != NULL) cmd->closecli (html_cli);
  296. }
  297.  
  298.  
  299. /*
  300.     Is called when a password is needed.
  301.     The proper information is sent to the www browser requesting such
  302.     a pawwword.
  303.  
  304.     The web browser will retransmit this password for the rest of
  305.     the session.
  306. */
  307. void html_needpasswd()
  308. {
  309.     html_printf ("HTTP/1.0 401 Unauthorized\r\n");
  310.     time_t tim = time(NULL);
  311.     char buf[200];
  312.     strcpy (buf,asctime(localtime(&tim)));
  313.     strip_end (buf);
  314.     html_printf ("Date: %s\r\n",buf);
  315.     extern char *revision;
  316.     html_printf ("Server: linuxconf/%s\r\n",revision);
  317.     html_printf ("WWW-Authenticate: Basic realm=\"root\"\r\n");
  318.     html_printf ("Content-type: text/html\r\n");
  319.     html_printf ("\r\n"
  320.         "<HEAD><TITLE>Authorization Required</TITLE></HEAD>\r\n"
  321.         "<BODY><H1>Authorization Required</H1>\r\n"
  322.         "This server could not verify that you\r\n"
  323.         "are authorized to access the document you\r\n"
  324.         "requested.  Either you supplied the wrong\r\n"
  325.         "credentials (e.g., bad password), or your\r\n"
  326.         "browser doesn't understand how to supply\r\n"
  327.         "the credentials required.<P>\r\n"
  328.         "</BODY>\r\n"
  329.         );
  330.     html_setdone();
  331. }
  332. PRIVATE void DIALOG::html_draw_top()
  333. {
  334.     html_sendintro ("text/html",-1,15);
  335.     html_printf (
  336.         "<HTML>\n"
  337.         "<HEAD>\n"
  338.         "<TITLE>%s:%s</TITLE>\n"
  339.         "</HEAD>\n"
  340.         "<BODY>\n",html_host,title.get());
  341.     for (int i=0; i<history_level; i++){
  342.         char path[PATH_MAX];
  343.         html_setpath_level (path,i);
  344.         char indent[20];
  345.         memset (indent,'.',sizeof(indent));
  346.         indent[i] = '\0';
  347.         html_printf ("<a href=\"/html:/%s\">%s%s</a>\n<br>\n"
  348.             ,path
  349.             ,indent
  350.             ,tblevel[i].title.get());
  351.     }
  352.     if (level > 0) html_printf ("<hr>\n");
  353. }
  354.  
  355. PRIVATE void DIALOG::html_draw_intro()
  356. {
  357.     if (!icon.is_empty()){
  358.         html_printf ("<img src=/images:images/%s.gif>\n",icon.get());
  359.     }
  360.     if (!intro.is_empty()){
  361.         html_printf ("<PRE>%s</PRE>\n\n<hr>\n",intro.get());
  362.     }
  363. }
  364.  
  365. PRIVATE void DIALOG::html_draw_fields()
  366. {
  367.     int lastf = getnb();
  368.     for (int i=0; i<lastf; i++) getitem(i)->html_draw (i);
  369. }
  370. PRIVATE void DIALOG::html_draw_form()
  371. {
  372.     char path[300];
  373.     html_setpath_level (path,target_level);
  374.     html_printf ("<form method=post action=/html:/%s>\n",path);
  375.     html_printf ("<CENTER>\n");
  376.     html_printf ("<TABLE border=1>\n");
  377.     if (curvars != NULL){
  378.         // Define variable for previous level
  379.         int n = curvars->getnb();
  380.         for (int i=0; i<n; i++){
  381.             const char *name = curvars->getvar(i);
  382.             if (isdigit(name[0]) && atoi(name)<level){
  383.                 html_printf ("<input type=hidden name=\"%s\" value=\"%s\">\n"
  384.                     ,name,curvars->getval(i));
  385.             }
  386.         }
  387.     }
  388.     html_draw_fields();
  389.     html_printf ("</TABLE>\n");
  390.     html_printf ("</CENTER>\n");
  391.     buttons->html_draw ();
  392.     html_printf ("</form>\n");
  393. }
  394. PRIVATE void DIALOG::html_draw_end()
  395. {
  396.     html_printf ("</BODY>\n</HTML>\n");
  397. }
  398. /*
  399.     Draw the complete dialog including a subdialog (error, password request)
  400. */
  401.  
  402. PRIVATE void DIALOG::html_draw (DIALOG *spc)
  403. {
  404.     /* #Specification: html mode / strategy / back on our feet
  405.         Maybe this is an already visited dialog. This has been visited
  406.         along the path followed while running through tblevel[]. While
  407.         doing so, we have stamp dialog title in each level (in
  408.         DIALOG::edithtml()). We will search now to see if we can find
  409.         this dialog title in tblevel and correct target_level accordingly.
  410.  
  411.         This situation happen with the following case:
  412.  
  413.         #
  414.             -The user is visiting one menu
  415.             -he selects one dialog
  416.             -he fills some fields and click on the "accept" button.
  417.             -A subdialog is poped
  418.             -The user fills it
  419.             -After some sub-sub-dialogs the job is done and we are
  420.              back to the original menu.
  421.         #
  422.  
  423.         All these steps have collected a longer and longer html path.
  424.         Each level of the path have captured the variable states used to
  425.         go the next. So we have a very long path, but we have to
  426.         fall on our feet again with a short path.
  427.     */
  428.     for (int i=0; i<target_level; i++){
  429.         if (tblevel[i].title.cmp(title) ==0){
  430.             target_level = i;
  431.             level = i;
  432.             break;
  433.         }
  434.     }
  435.     html_draw_top();
  436.     if (spc != NULL){
  437.         spc->html_draw_intro();
  438.         spc->html_draw_fields();
  439.         html_printf ("<hr>\n");
  440.     }
  441.     html_draw_intro();
  442.     html_draw_form();
  443.     html_draw_end();
  444. }
  445. /*
  446.     Draw the complete dialog
  447. */
  448.  
  449. PRIVATE void DIALOG::html_draw ()
  450. {
  451.     html_draw(NULL);
  452. }
  453. /*
  454.     Load all field of the dialog with the received value
  455.     and check that everything is valid
  456.     Return -1 if any error.
  457. */
  458.  
  459. PRIVATE int DIALOG::html_validate ()
  460. {
  461.     int ret = 0;
  462.     int lastf = getnb();
  463.     for (int i=0; i<lastf; i++) ret |= getitem(i)->html_validate (i);
  464.     return ret;
  465. }
  466.  
  467. PUBLIC void BUTTONS_INFO::html_draw()
  468. {
  469.     for (int i=0; i<nb; i++){
  470.         MENU_STATUS code = tbret[i];
  471.         const char *name = "nil";
  472.         if (code == MENU_HELP){
  473.             html_printf ("<a href=\"http:/help:%s.html\">"
  474.                 "<img src=/images:images/%s.gif></a>\n"
  475.                 ,helpfile.get()+strlen(USR_LIB_LINUXCONF)+1
  476.                 ,tb[i]);
  477.         }else{
  478.             if (code == MENU_CANCEL
  479.                 || code == MENU_QUIT
  480.                 || code == MENU_OK){
  481.                 continue;    // Those buttons are useless in html mode
  482.             }else if (code == MENU_ACCEPT){
  483.                 name = KEY_ACCEPT;
  484.             }else if (code == MENU_ADD){
  485.                 name = KEY_ADD;
  486.             }else if (code == MENU_SAVE){
  487.                 name = "save";
  488.             }else if (code == MENU_DEL){
  489.                 name = KEY_DEL;
  490.             }else if (code == MENU_EDIT){
  491.                 name = KEY_EDIT;
  492.             }else if (code == MENU_YES){
  493.                 name = KEY_YES;
  494.             }else if (code == MENU_NO){
  495.                 name = KEY_NO;
  496.             }else{
  497.                 printf ("old button\n");
  498.                 #if 0
  499.                 char path[PATH_MAX];
  500.                 html_setpath (path);
  501.                 html_printf ("<a href=\"http://%s:%d/button:%s:%s\">%s</a>\n"
  502.                     ,html_host
  503.                     ,port
  504.                     ,tb[i]
  505.                     ,path
  506.                     ,tb[i]);
  507.                 #endif
  508.             }
  509.             html_printf ("<input type=image name=%s "
  510.                  "src=/images:images/%s.gif>\n"
  511.                 ,name,tb[i]);
  512.         }
  513.     }
  514. }
  515.  
  516. static DIALOG *html_postdialog;
  517.  
  518. void html_forgetdialog (DIALOG *dia)
  519. {
  520.     if (dia == html_postdialog){
  521.         html_postdialog = NULL;
  522.         #if 0
  523.         if (!html_drawdone){
  524.             // The next time we will get in edithtml, level is still equal
  525.             // to target_level, so html_draw will be called
  526.             // providing the next page to www user. This is a hack.
  527.             // After an accept, we are back to the previous menu
  528.             target_level--;
  529.             level--;
  530.         }
  531.         #endif
  532.     }
  533. }
  534.  
  535. /* #Specification: html mode / general strategy
  536.     Here is a basic explanation of the way linuxconf manage html page
  537.     while not being that much http/html aware.
  538.  
  539.     Some fact:
  540.  
  541.     #
  542.     -Linuxconf is a classical modal program. Mostly, only one dialog has
  543.      the focus at a time. Further, in linuxconf, there is generally
  544.      only one dialog at once. This is acceptable for admin tasks anyway.
  545.     -html mode work with the concept of hope. You send a page to a
  546.      user and he may click on a button one day or never. You better
  547.      not wait for it. So good for a modal program.
  548.     #
  549.  
  550.     The strategy is simple. Linuxconf is always waiting at the
  551.     top level of the menu hierachy for an html request. Each request
  552.     contain a path (using /'s) allowing linuxconf to navigate
  553.     in the menu hisrarchy up to a certain "level". At this point
  554.     linuxconf simply draw the dialog or menu and ... get back
  555.     to the top level.
  556.  
  557.     This behavior of always getting back is trigger by returning
  558.     MENU_ESCAPE, so each part of linuxconf must be "ESCAPE" aware, which
  559.     is good anyway.
  560.  
  561.     So when we get a path, we parse it and store it in a table
  562.     and note the target_level.
  563.  
  564.     Important assumption here:
  565.  
  566.     All dialog with input are preceded in the hierarchy by menus.
  567.     This make sens anyway. This disable support for popup dialog
  568.     however.
  569.  
  570.     So we parse and store the path and lauch linuxconf from the top
  571.     level menu. While navigating in its code, linuxconf draw menus
  572.     (not really) and wait for input (not really also). If this
  573.     menu is not of the proper level, the path information will be
  574.     used as a key to identify which menu item was choosen. A MENU_OK
  575.     is then returned and linuxconf continue to navigate further into
  576.     sub-sub-menus (In fact the exact button returned is contain
  577.     in the path). At some point, it crosses the target level.
  578.  
  579.     At the target level, there is two cases:
  580.  
  581.     Either this is GET or a POST. If this is a GET, we draw the dialog
  582.     and escape away to the main loop. If this is a POST, then we
  583.     load all the fields of the dialog with the values received from
  584.     the POST.
  585.  
  586.     Based on some special values, we know which buttons was hit and
  587.     return appropriatly MENU_ACCEPT, MENU_ADD and so on to the
  588.     application. Three things may happen. Either there is some error
  589.     message (The application identify those with html_setpopup())
  590.     or linuxconf is happy and exited to the previous level menu (Leaving
  591.     this dialog screen) or linuxconf provide a sub-dialog asking for
  592.     more info.
  593.  
  594.     Most of the logic here is controlled by the DIALOG::edithtml()
  595.     function.
  596. */
  597.  
  598. /*
  599.     Record that the next DIALOG object is a popup dialog (error message)
  600. */
  601. void html_setpopup()
  602. {
  603.     html_popup = 1;
  604. }
  605. PRIVATE MENU_STATUS DIALOG::edithtml(int &nof)
  606. {
  607.     MENU_STATUS ret = MENU_ESCAPE;
  608.     if (!html_drawdone){
  609.         static SSTRING top_str;
  610.         static SSTRING bottom_str;
  611.         if (level == target_level){
  612.             static MENU_STATUS was_button;    // Was it a POST with the
  613.                                             // button accept
  614.             if (curvars != NULL && !html_postdone){
  615.                 //html_postdialog = this;
  616.                 if (html_validate() != -1){
  617.                     // Those names need not be translated
  618.                     // see BUTTONS_INFO::html_draw()
  619.                     if (html_butexist("ok.x")){
  620.                         ret = MENU_OK;
  621.                     }else if (html_butexist("accept.x")){
  622.                         ret = MENU_ACCEPT;
  623.                     }else if (html_butexist("add.x")){
  624.                         ret = MENU_ADD;
  625.                     }else if (html_butexist("edit.x")){
  626.                         ret = MENU_EDIT;
  627.                     }else if (html_butexist("del.x")){
  628.                         ret = MENU_DEL;
  629.                     }else if (html_butexist("save.x")){
  630.                         ret = MENU_SAVE;
  631.                     }else if (html_butexist("yes.x")){
  632.                         ret = MENU_YES;
  633.                     }else if (html_butexist("no.x")){
  634.                         ret = MENU_NO;
  635.                     }else{
  636.                         if (debug) fprintf (stderr,"Invalid button\n");
  637.                         ret = MENU_CANCEL;
  638.                     }
  639.                     was_button = ret;
  640.                     html_postdone = 1;
  641.                     html_draw_top();
  642.                     top_str.setfrom (html_buf);
  643.                     html_len = 0;
  644.                     html_draw_intro();
  645.                     html_draw_form();
  646.                     html_draw_end();
  647.                     bottom_str.setfrom(html_buf);
  648.                     html_len = 0;
  649.                 }else{
  650.                     html_printf ("500 %s\r\n"
  651.                         ,MSG_U(E_MISMATCH,"dialog state mismatch"));
  652.                     html_setdone();
  653.                 }
  654.             }else{
  655.                 if (curvars != NULL){
  656.                     if (html_popup){
  657.                         top_str.copy (html_buf);
  658.                         html_len = strlen (html_buf);
  659.                         html_draw_intro();
  660.                         html_draw_fields();
  661.                         bottom_str.copy (html_buf+html_len);
  662.                         html_len = strlen (html_buf);
  663.                     }else{
  664.                         if (was_button == MENU_ACCEPT && 0){
  665.                             // We have accepted so we get back to
  666.                             // previous menu
  667.                             target_level--;
  668.                             level--;
  669.                         }else{
  670.                             tblevel[level].status = was_button;
  671.                             target_level++;
  672.                             level++;
  673.                         }
  674.                         html_draw();
  675.                     }
  676.                 }else{
  677.                     html_draw();
  678.                 }
  679.                 html_setdone();
  680.             }
  681.         }else if (level < target_level){
  682.             LEVEL_INFO *pt = tblevel + level;
  683.             pt->title.setfrom (title);
  684.             int n = getnb();
  685.             nof = -1;
  686.             for (int i=0; i<n; i++){
  687.                 char key[PATH_MAX];
  688.                 getitem(i)->format_htmlkey(key,i);
  689. printf ("Compare :%s: :%s:\n",key,pt->key.get());
  690.                 if (pt->key.cmp(key)==0){
  691.                     nof = i;
  692.                     break;
  693.                 }
  694.             }
  695.             if (nof == -1
  696.                 && pt->status  == MENU_OK){
  697.                 html_printf ("500 %s\r\n",MSG_U(E_IVLDURL,"Invalid URL\n"));
  698. printf ("Et ne trouve pas %d\n",pt->status);
  699.                 html_setdone();
  700.             }else{
  701.                 ret = pt->status;
  702.                 {
  703.                     #if 0
  704.                         // We have to reestablish the context at the moment
  705.                         // of the original POST which has happen at this
  706.                         // level in a previous session
  707.                         char context[200];
  708.                         html_setcontext_level(context,level);
  709.                         HTML_VARVAL *lv = varval_get(context);
  710.                         if (lv != NULL){
  711.                             HTML_VARVAL *cur = curvars;
  712.                             curvars = lv;
  713.                             if (html_validate() == -1){
  714.                                 html_printf ("500 %s\r\n",MSG_R(E_MISMATCH));
  715.                                 html_setdone();
  716.                             }
  717.                             curvars = cur;
  718.                         }
  719.                     #else
  720.                         printf ("Intermediate validate level %d %d\n",level,ret);
  721.                         if (html_validate() == -1){
  722.                             html_printf ("500 %s\r\n",MSG_R(E_MISMATCH));
  723.                             html_setdone();
  724.                         }
  725.                         printf ("Intermediate validate level %d end\n",level);
  726.                     #endif
  727.                 }
  728.                     
  729.             }
  730.             level++;
  731.         }
  732.     }
  733.     return ret;
  734. }
  735.  
  736. static void html_parsepath(char *pt)
  737. {
  738.     if (debug) fprintf (stderr,"Parse path :%s:\n",pt);
  739.     int len = strlen(pt);
  740.     if (len > 0 && pt[len-1] == '/') pt[len-1] = '\0';
  741.     history_level = level = target_level = 0;
  742.     if (pt[0] == '/') pt++;
  743.     while (*pt != '\0'){
  744.         char *split = strchr (pt,'/');
  745.         if (split != NULL) *split++ = '\0';
  746.         char *comma = strchr(pt,',');
  747.         if (comma != NULL){
  748.             *comma++ = '\0';
  749.             if (comma[0] != '\0') history_level++;
  750.         }
  751.         LEVEL_INFO *ptl = &tblevel[target_level++];
  752.         ptl->key.setfrom (comma);
  753.         if (strcmp(pt,KEY_OK)==0){
  754.             ptl->status = MENU_OK;
  755.         }else if (strcmp(pt,KEY_ACCEPT)==0){
  756.             ptl->status = MENU_ACCEPT;
  757.         }else if (strcmp(pt,KEY_ADD)==0){
  758.             ptl->status = MENU_ADD;
  759.         }else if (strcmp(pt,KEY_DEL)==0){
  760.             ptl->status = MENU_DEL;
  761.         }else if (strcmp(pt,KEY_YES)==0){
  762.             ptl->status = MENU_YES;
  763.         }else if (strcmp(pt,KEY_NO)==0){
  764.             ptl->status = MENU_NO;
  765.         }else if (strcmp(pt,KEY_EDIT)==0){
  766.             ptl->status = MENU_EDIT;
  767.         }
  768.         if (split != NULL){
  769.             pt = split;
  770.         }else{
  771.             break;
  772.         }
  773.     }
  774. }
  775. static void html_dbglog (const char *title, const char *str)
  776. {
  777.     FILE *f = fopen ("/tmp/li.dbg","a");
  778.     if (f != NULL){
  779.         fprintf (f,"======%s=======\n",title);
  780.         fputs (str,f);
  781.         fclose (f);
  782.     }
  783. }
  784.  
  785. static char hextoi (char asc)
  786. {
  787.     return isdigit(asc) ? asc - '0' : (toupper(asc) - 'A') + 10;
  788. }
  789.  
  790. static const char *html_decode (const char *str, char *buf)
  791. {
  792.     char *pt = buf;
  793.     while (*str != '\0' && *str != '\n'){
  794.         if (*str == '%'){
  795.             str++;
  796.             *pt++ = hextoi(*str++) * 16 + hextoi(*str++);
  797.         }else if (*str == '+'){
  798.             *pt++ = ' ';
  799.             str++;
  800.         }else{
  801.             *pt++ = *str++;
  802.         }
  803.     }
  804.     *pt = '\0';
  805.     strip_end (buf);
  806.     if (*str == '\n') str++;
  807.     return str;
  808. }
  809.  
  810. static void html_parsevar (const char *buf)
  811. {
  812.     {
  813.         char context[200];
  814.         html_setcontext_level(context,target_level);
  815.         curvars = new HTML_VARVAL(context);
  816.     }
  817.     while (1){
  818.         char *pt = strchr(buf,'=');
  819.         if (pt == NULL){
  820.             break;
  821.         }else{
  822.             *pt++ = '\0';
  823.             char *end = strchr(pt,'&');
  824.             if (end != NULL){
  825.                 *end++ = '\0';
  826.             }
  827.             char var[200];
  828.             char val[2000];
  829.             html_decode (buf,var);
  830.             html_decode (pt,val);
  831.             curvars->add (var,val);
  832.             if (end == NULL) break;
  833.             buf = end;
  834.         }
  835.     }
  836. }
  837. /*
  838.     Parse a potentially completed header.
  839.     Extract the "get" command or "post" command.
  840.  
  841.     Return -1 if any error.
  842.     Return  0 if the header was not completed
  843.     Return  1 if the header was completed
  844. */
  845. static int html_parse (
  846.     const char *str,
  847.     char *file_request,        // Will contain a file to transmit to the client
  848.     char *username,        // Will hold the username
  849.     char *password,        // and password provided by the browser
  850.     HELP_FILE &intro)
  851. {
  852.     unsigned expected_length = 0;
  853.     int html_post = 0;
  854.     int ret = 0;
  855.     int get_ok = 0;
  856.     file_request[0] = '\0';
  857.     html_java = 0;
  858.     html_submit = MENU_NULL;
  859.     username[0] = '\0';
  860.     password[0] = '\0';
  861.     while (*str != '\0'){
  862.         char buf[10000];
  863.         str = html_decode (str,buf);
  864.         if (buf[0] == '\0'){
  865.             if (get_ok){
  866.                 html_reset();
  867.                 if (html_post){
  868.                     char t[100];
  869.                     sprintf (t,"expe %u, got %u\n",expected_length,strlen(str));
  870.                     html_dbglog ("detail",t);
  871.                     if (strlen(str) >= expected_length){
  872.                         strcpy (buf,str);
  873.                         html_parsevar (buf);
  874.                         ret = 1;
  875.                     }
  876.                     break;
  877.                 }else{
  878.                     ret = 1;
  879.                 }
  880.             }else{
  881.                 ret = -1;
  882.             }
  883.         }else{
  884.             char cmd[200];
  885.             char *pt = str_copyword (cmd,buf);
  886.             strupr (cmd);
  887.             int is_get = strcmp(cmd,"GET")==0;
  888.             int is_post = strcmp(cmd,"POST")==0;
  889.             if (is_get || is_post){
  890.                 pt = str_skip (pt);
  891.                 char path[1000];
  892.                 char parm[1000];
  893.                 parm[0] = '\0';
  894.                 str_copyword (path,pt);
  895.                 char *ptparm = strchr(path,'?');
  896.                 if (ptparm != NULL){
  897.                     *ptparm++ = '\0';
  898.                     strcpy (parm,ptparm);
  899.                 }
  900.                 if (strncmp(path,"/help:",6)==0){
  901.                     strcpy (file_request,path+6);
  902.                 }else if (strncmp(path,"/images:",8)==0){
  903.                     strcpy (file_request,path+8);
  904.                 }else if (strncmp(path,"/java:",6)==0){
  905.                     html_java = 1;
  906.                     html_parsepath(path+6);
  907.                 }else if (strncmp(path,"/html:",6)==0){
  908.                     html_parsepath(path+6);
  909.                 #if 0
  910.                     }else if (strncmp(path,"/button:",8)==0){
  911.                         char *pt = path + 8;
  912.                         // No need to make this translatable
  913.                         static struct BUT_LKP{
  914.                             const char *name;
  915.                             MENU_STATUS but;
  916.                         }tb[]={
  917.                             {"add",    MENU_ADD},
  918.                             {"del",    MENU_DEL},
  919.                             {"save",    MENU_ADD},
  920.                             {"accept",    MENU_ACCEPT},
  921.                         };
  922.                         BUT_LKP *ptb = tb;
  923.                         for (unsigned i=0; i<sizeof(tb)/sizeof(tb[0])
  924.                             ; i++, ptb++){
  925.                             int len = strlen(ptb->name);
  926.                             if (strncmp(ptb->name,pt,len)==0
  927.                                 && pt[len] == ':'){
  928.                                 html_parsepath(pt + len + 1);
  929.                                 html_submit = ptb->but;
  930.                                 break;
  931.                             }
  932.                         }
  933.                 #endif
  934.                 }else{
  935.                     strcpy (file_request,intro.getpath()+strlen(USR_LIB_LINUXCONF)+1);
  936.                     strcat (file_request,".html");
  937.                 }
  938.                 html_post = is_post;
  939.                 get_ok = 1;
  940.             }else if (stricmp(cmd,"Content-length:")==0){
  941.                 expected_length = atoi(pt);
  942.             }else if (stricmp(cmd,"Authorization:")==0){
  943.                 char basic[1000];
  944.                 pt = str_copyword (basic,pt);
  945.                 if (stricmp(basic,"Basic")==0){
  946.                     pt = str_copyword (basic,pt);
  947.                     char pw[1000];
  948.                     base64_decode(pw,basic);
  949.                     char *ptpt = strchr(pw,':');
  950.                     if (ptpt != NULL){
  951.                         *ptpt++ = '\0';
  952.                         strcpy (username,pw);
  953.                         strcpy (password,ptpt);
  954.                     }
  955.                 }
  956.             }
  957.         }
  958.     }
  959.     return ret;
  960. }
  961.  
  962. static void html_copy (const char *fname)
  963. {
  964.     char path[PATH_MAX];
  965.     sprintf (path,"%s/%s",USR_LIB_LINUXCONF,fname);
  966.     if (debug) fprintf (stderr,"Sending :%s:\n",path);
  967.     FILE *fin = fopen (path,"r");
  968.     if (fin == NULL){
  969.         html_printf ("500 file %s not found\r\n",fname);
  970.         html_flush();
  971.     }else{
  972.         struct stat st;
  973.         int size = -1;
  974.         if (stat(path,&st)!=-1) size = st.st_size;
  975.         html_sendintro(strstr(fname,".gif")!=NULL ? "image/gif" : "text/html"
  976.             ,size,4*60*60);
  977.         html_flush();
  978.         char buf[10000];
  979.         int n;
  980.         while ((n=fread(buf,1,sizeof(buf),fin))> 0){
  981.             //if (debug) fwrite (buf,1,n,stderr);
  982.             write (html_cli,buf,n);
  983.         }
  984.         html_printf ("\r\n");
  985.         html_flush();
  986.         fclose (fin);
  987.     }
  988. }
  989.  
  990.  
  991. static SSTRING *tbs[200];
  992.  
  993. /*
  994.     Get a command (A "get" indeed) from a client (Web browser).
  995.     parse this command into a path that will silently show the way
  996.     so linuxconf will silently travel to the proper menu, draw it
  997.     and quit.
  998.  
  999.     Return -1 if there was some error or nothing has happen
  1000.     for a long time (no more job). Nothing to do for Linuxconf.
  1001. */
  1002. int html_get (int _debug, HELP_FILE &intro)
  1003. {
  1004.     debug = _debug;
  1005.     if (cmd == NULL) cmd = new CMDSOCK (debug ? port : -1);
  1006.     int ret = -1;
  1007.     while (1){
  1008.         if (cmd->listen(600*1000000) <= 0){
  1009.             break;
  1010.         }else{
  1011.             char buf[1000];
  1012.             int nb;
  1013.             int cli;
  1014.             if ((nb=cmd->readnext (buf,sizeof(buf)-1,cli))>=0){
  1015.                 if (nb == 0){
  1016.                     cmd->closecli (cli);
  1017.                 }else if (tbs[cli] == NULL
  1018.                     && html_access_check(cli)!=0){
  1019.                     html_cli = cli;
  1020.                     html_printf ("500 access denied\r\n");
  1021.                     html_flush();
  1022.                     cmd->closecli (cli);
  1023.                 }else{
  1024.                     buf[nb] = '\0';
  1025.                     if (tbs[cli] == NULL){
  1026.                         tbs[cli] = new SSTRING;
  1027.                     }
  1028.                     tbs[cli]->append (buf);
  1029.                     if (tbs[cli]->getlen()>10000){
  1030.                         /* #Specification: html mode / input overflow
  1031.                             If linuxconf receive an http request exceding
  1032.                             10000 bytes, it is silently flushed.
  1033.                         */
  1034.                         cmd->closecli(cli);
  1035.                         delete tbs[cli];
  1036.                         tbs[cli] = NULL;
  1037.                     }else{
  1038.                         char file_request[PATH_MAX];
  1039.                         char username[50];
  1040.                         char password[50];
  1041.                         html_dbglog ("so far",tbs[cli]->get());
  1042.                         int ok = html_parse (tbs[cli]->get(),file_request
  1043.                             ,username,password,intro);
  1044.                         perm_setaccess(username,password);
  1045.                         if (ok == -1){
  1046.                             cmd->closecli (cli);
  1047.                             delete tbs[cli];
  1048.                             tbs[cli] = NULL;
  1049.                         }else if (ok > 0){
  1050.                             html_cli = cli;
  1051.                             delete tbs[cli];
  1052.                             tbs[cli] = NULL;
  1053.                             if (file_request[0] != '\0'){
  1054.                                 html_copy (file_request);
  1055.                                 cmd->closecli (cli);
  1056.                             }else{
  1057.                                 ret = 0;
  1058.                                 break;
  1059.                             }
  1060.                         }
  1061.                     }
  1062.                 }
  1063.             }
  1064.         }
  1065.     }
  1066.     return ret;
  1067. }
  1068.  
  1069.  
  1070.